package com.xuxueli.xxlrpc.remoting.net.impl.netty.server;

import com.xuxueli.xxlrpc.remoting.net.Server;
import com.xuxueli.xxlrpc.remoting.net.impl.netty.codec.NettyDecoder;
import com.xuxueli.xxlrpc.remoting.net.impl.netty.codec.NettyEncoder;
import com.xuxueli.xxlrpc.remoting.net.params.Beat;
import com.xuxueli.xxlrpc.remoting.net.params.XxlRpcRequest;
import com.xuxueli.xxlrpc.remoting.net.params.XxlRpcResponse;
import com.xuxueli.xxlrpc.remoting.provider.XxlRpcProviderFactory;
import com.xuxueli.xxlrpc.util.ThreadPoolUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author：YH
 * @Description：
 * @Date:Created in 2022/5/31 18:21
 */
public class NettyServer extends Server {

    private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);

    private Thread thread;

    @Override
    public void start(XxlRpcProviderFactory xxlRpcProviderFactory) throws Exception {

        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                logger.info("NettyServer.run绑定过滤器心跳检测");
                ThreadPoolExecutor serverHandlerPool =
                        ThreadPoolUtil.makeServerThreadPool(NettyServer.class.getSimpleName(),
                                xxlRpcProviderFactory.getCorePoolSize(), xxlRpcProviderFactory.getMaxPoolSize());
                EventLoopGroup bossGroup = new NioEventLoopGroup();
                EventLoopGroup workerGroup = new NioEventLoopGroup();

                try {
                    ServerBootstrap bootstrap = new ServerBootstrap();
                    bootstrap.group(bossGroup, workerGroup)
                            .channel(NioServerSocketChannel.class)
                            .childHandler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                protected void initChannel(SocketChannel channel) throws Exception {
                                    channel.pipeline()
                                            .addLast(new IdleStateHandler(0, 0, Beat.BEAT_INTERVAL * 3,
                                                    TimeUnit.SECONDS))     // beat 3N, close if idle
                                            .addLast(new NettyDecoder(XxlRpcRequest.class,
                                                    xxlRpcProviderFactory.getSerializerInstance()))
                                            .addLast(new NettyEncoder(XxlRpcResponse.class,
                                                    xxlRpcProviderFactory.getSerializerInstance()))
                                            .addLast(new NettyServerHandler(xxlRpcProviderFactory, serverHandlerPool));

                                }
                            })
                            .childOption(ChannelOption.TCP_NODELAY, true)
                            .childOption(ChannelOption.SO_KEEPALIVE, true);
                    // bind
                    ChannelFuture future = bootstrap.bind(xxlRpcProviderFactory.getPort()).sync();
                    logger.info(">>>>>>>>>>> 绑定端口服务端启动xxl-rpc remoting server start success, nettype = {}, port = {}"
                            , NettyServer.class.getName(), xxlRpcProviderFactory.getPort());
                    onStarted();

                    // wait util stop
                    future.channel().closeFuture().sync();
                } catch (Exception e) {
                    if (e instanceof InterruptedException) {
                        logger.info(">>>>>>>>>>> xxl-rpc remoting server stop.");
                    } else {
                        logger.error(">>>>>>>>>>> xxl-rpc remoting server error.", e);
                    }
                } finally {
                    // stop
                    try {
                        serverHandlerPool.shutdown();    // shutdownNow
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                    try {
                        workerGroup.shutdownGracefully();
                        bossGroup.shutdownGracefully();
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                    }
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
        thread.setName("NettyServer-Thread");
    }

    @Override
    public void stop() throws Exception {
//        // destroy server thread
//        if (thread != null && thread.isAlive()) {
//            thread.interrupt();
//        }
//        // on stop
//        onStoped();
//        logger.info(">>>>>>>>>>> xxl-rpc remoting server destroy success.");
    }
}
